
#include <system.h>
#include <stdlib.h>
#include <unistd.h>
#include <common.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iconv.h>
#include <openssl/md5.h>

void system_init(void)
{
	time_t time_seconds = time(NULL);
    struct tm now_time;
	//struct rlimit coreFileSize;

    localtime_r(&time_seconds, &now_time);
 
    DEBUG("%d-%d-%d %d:%d:%d tm_wday:%d\n", now_time.tm_year + 1900, now_time.tm_mon + 1,
        now_time.tm_mday, now_time.tm_hour, now_time.tm_min, now_time.tm_sec, now_time.tm_wday);

	if(now_time.tm_year < 100) {
		set_time("2000/1/1 9:0:55");
	}

	//prctl(PR_SET_DUMPABLE, 1);
	//getrlimit(RLIMIT_CORE, &coreFileSize);
	//coreFileSize.rlim_cur = RLIM_INFINITY;
	//coreFileSize.rlim_max = RLIM_INFINITY;
	//setrlimit(RLIMIT_CORE, &coreFileSize);

	mkdir(WARN_RECORD_PATH, S_IRWXU|S_IRWXG|S_IRWXO);
	mkdir(VOICE_FILE_PATH, S_IRWXU|S_IRWXG|S_IRWXO);
	mkdir(FIRMWARE_PATH, S_IRWXU|S_IRWXG|S_IRWXO);
	mkdir(BROADCAST_TASK_PATH, S_IRWXU|S_IRWXG|S_IRWXO);
	mkdir(BROADCAST_FILE_PATH, S_IRWXU|S_IRWXG|S_IRWXO);
}

void millisecond_sleep(unsigned long milliseconds)
{
	usleep(1000*milliseconds);
}

void second_sleep(unsigned int seconds)
{
	sleep(seconds);
}

int isFileExists(const char *path)
{
	return !access(path, F_OK);
}

int myexec(char *command, char *result, int *maxline)
{
	char tmp[1024] = {0};
	FILE *pp = popen(command, "r");
	if(NULL == pp)
	{
		return -1;
	}

	if(result != NULL)
	{
		int line=0;
		while(fgets(tmp, sizeof(tmp), pp) != NULL)
		{
			//DEBUG("%s", tmp);
			if('\n' == tmp[strlen(tmp) - 1]) tmp[strlen(tmp) - 1] = '\0';
			if(maxline != NULL && line++<*maxline) strcat(result, tmp);
		}
		*maxline = line;
	}

	return pclose(pp);
}

void thread_sigmask(void)
{
	//sigset_t sigmask;
	//sigemptyset(&sigmask);
	//sigaddset(&sigmask, SIGALRM);
	//pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
}

static void *routine_thread(void *arg)
{
	struct thread_desc {
		pthread_t tid;
		void *(*thread)(void *);
		void *param;
	};
	
	struct thread_desc *desc = arg;
	thread_sigmask();
	desc->thread(desc->param);
	free(desc);
	return NULL;
}

void create_thread(void *(*start_routine)(void *), void *param)
{
	struct thread_desc {
		pthread_t tid;
		void *(*thread)(void *);
		void *param;
	};

	struct thread_desc *desc = malloc(sizeof(struct thread_desc));
	desc->param = param;
	desc->thread = start_routine;
	pthread_create(&desc->tid, NULL, routine_thread, desc);
}

int ethernet_not_connect(char *ifname)
{
	int rslt = 1;
	int skfd;
	struct ifreq ifr;

	skfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(skfd > 0)
	{
		strcpy(ifr.ifr_name, ifname);
		if(ioctl(skfd, SIOCGIFADDR, &ifr) == 0)
		{
			rslt = 0;
		}
		close(skfd);
	}

	return rslt;
}

char* get_eth_mac(char *ifname, char *mac)
{
	int i = 0;
	int sock = 0;
	struct ifreq ifreq;

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if(sock > 0)
	{
		strcpy(ifreq.ifr_name, ifname);
		if(ioctl(sock, SIOCGIFHWADDR, &ifreq) == 0)
		{
			for(i = 0; i < 6; i++)
			{
				sprintf(&mac[2*i], "%02X", (unsigned char)ifreq.ifr_hwaddr.sa_data[i]);
			}
		}
		close(sock);
	}

	return mac;
}

char* get_eth_ip(char *ifname, char *ip)
{
	int sock = 0;
	struct ifreq ifreq;
	struct sockaddr_in sin;

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if(sock > 0)
	{
		strcpy(ifreq.ifr_name, ifname);
		if(ioctl(sock, SIOCGIFADDR, &ifreq) == 0)
		{
			memcpy(&sin, &ifreq.ifr_dstaddr, sizeof(struct sockaddr_in));
			strcpy(ip, inet_ntoa(sin.sin_addr));
		}
		close(sock);
	}

	return ip;
}


int set_time(char *date)
{
	int ret = 0;
    struct tm set_tm = {0};
    struct timeval tv = {0};

	ret = sscanf(date, "%d/%d/%d %d:%d:%d", &set_tm.tm_year, &set_tm.tm_mon, &set_tm.tm_mday, &set_tm.tm_hour, &set_tm.tm_min, &set_tm.tm_sec);
	if(ret == 6)
	{
		set_tm.tm_mon = set_tm.tm_mon - 1;
		set_tm.tm_year = set_tm.tm_year - 1900;
		tv.tv_sec = mktime(&set_tm);
		tv.tv_usec = 0;
		settimeofday(&tv, NULL);
		return 0;
	}

	DEBUG("set time fail ret=%d", ret);
	return -1;
}

int string2hex(unsigned char *dest, char *src)
{
	int i;
	char str[3] = {0};
	int destlen;	
	int srclen;

	srclen = strlen(src);
	if((srclen % 2) > 0)
	{
		//长度为单数
		srclen += 1;
	}

	destlen = srclen/2;
	for(i=0; i<destlen; i++)
	{
		str[0] = src[i*2];
		str[1] = src[i*2 + 1];
		dest[i] = strtoul(str, NULL, 16);
	}

	return destlen;
}

int string2hex_reverse(unsigned char *dest, char *src)
{
	int i;
	char str[3] = {0};
	int destlen;
	int srclen;

	srclen = strlen(src);
	if((srclen % 2) > 0)
	{
		//长度为单数
		srclen += 1;
	}

	destlen = srclen/2;
	for(i=0; i<destlen; i++)
	{
		str[0] = src[i*2];
		str[1] = src[i*2 + 1];
		dest[destlen-i-1] = strtoul(str, NULL, 16);
	}

	return destlen;
}

void hex2string(char *dest, unsigned char *src, int srclen)
{
	int i;
	
	int val_h;
	int val_l;
	
	for(i=0; i<srclen; i++)
	{
		val_h = (src[i] >> 4) & 0xf;
		val_l = src[i] & 0xf;
		dest[2*i] = val_h < 10 ? val_h + '0' : val_h - 10 + 'A';
		dest[2*i + 1] = val_l < 10 ? val_l + '0' : val_l - 10 + 'A';
	}
}

void hex2string_lowercase(char *dest, unsigned char *src, int srclen)
{
	int i;
	
	int val_h;
	int val_l;
	
	for(i=0; i<srclen; i++)
	{
		val_h = (src[i] >> 4) & 0xf;
		val_l = src[i] & 0xf;
		dest[2*i] = val_h < 10 ? val_h + '0' : val_h - 10 + 'a';
		dest[2*i + 1] = val_l < 10 ? val_l + '0' : val_l - 10 + 'a';
	}
}

//保存网关节点cJSON信息到本地
void save_root_to_file(cJSON *root, char *file_name)
{
	int fd;
	char *out;
	fd = open(file_name, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
	if(fd > 0)
	{
		//out = cJSON_PrintUnformatted(root);
		out = cJSON_Print(root);
		lseek(fd, 0, SEEK_SET);
		if(ftruncate(fd, 0))
		{
			DEBUG("ftruncate error");
		}

		if(write(fd, out, strlen(out)) < 0)
		{
			DEBUG("write error");
		}

		fsync(fd);
		close(fd);
		free(out);
	}
}

int get_file_size(char *file_name)
{
	struct stat file_stat;
	stat(file_name, &file_stat);
	return file_stat.st_size;
}

cJSON *parse_root_from_file(char *file_name)
{
	int fd;
	cJSON *root = NULL;
	char *out;
	struct stat file_stat;
	
	fd = open(file_name, O_RDWR);
	if(fd > 0)
	{
		fstat(fd, &file_stat);
		out = malloc(file_stat.st_size + 1);
		memset(out, 0, file_stat.st_size + 1);
		if(read(fd, out, file_stat.st_size) < 0)
		{
			DEBUG("read error");
		}
		root = cJSON_Parse(out);
		free(out);
		close(fd);
		return root;
	}
	else
	{
		//DEBUG("%s not exist", file_name);
	}

	return NULL;
}

//释放cJSON内存
void free_root(cJSON *root)
{
	if(root)
	{
		cJSON_Delete(root);
	}
}

//获取微妙
long long get_microsecond(void)
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return tv.tv_sec * 1000000 + tv.tv_usec;
}

//获取毫秒
long long get_millisecond(void)
{
	return get_microsecond()/1000;
}

long long generate_msgid(void)
{
	//return get_microsecond();
	return time(NULL);
}


int charset_convert(const char *from_charset, const char *to_charset, char *in_buf, size_t in_left, char *out_buf, size_t out_left)
{
	iconv_t icd = (iconv_t) -1;
	size_t  ret = -1;
	size_t  outLen = out_left;

	icd = iconv_open(to_charset, from_charset);
	if  ((iconv_t)-1 == icd)
	{
		perror("iconv_open");
		return  0;
	}

	ret = iconv(icd, &in_buf, &in_left, &out_buf, &out_left);
	if(( size_t )-1 == ret)
	{
		perror("iconv");
		iconv_close(icd);
		return  0;
	}

	iconv_close(icd);
	return outLen - out_left;
}

int charset_convert_UTF8_TO_GB2312(char *in_buf, int in_left, char *out_buf, int out_left)
{
	return charset_convert("UTF-8", "GB2312", in_buf, in_left, out_buf, out_left);
}

#define HT_NOR_LOG_TAG 			"BasicControl-service"
#define HT_NOR_LOG_OPTION 		LOG_PID|LOG_NDELAY
#define HT_NOR_LOG_FAC 			LOG_LOCAL0

static void NormalLog(char *pLog)
{
	openlog(HT_NOR_LOG_TAG, HT_NOR_LOG_OPTION, HT_NOR_LOG_FAC);
	syslog(LOG_INFO ,"%s", pLog);
	closelog();
	//printf(pLog);
}

void log_printf(const char *fmt,...)
{
	char ucBuf[1024];
	va_list args;
	va_start(args, fmt);
	vsnprintf(ucBuf, 1000, fmt, args);
	NormalLog(ucBuf);
	va_end(args);
}


int get_current_minute(void)
{
    time_t rawtime;
    struct tm * timeinfo;
    
    time(&rawtime); // 获取当前时间戳
    timeinfo = localtime(&rawtime); // 转换为本地时间
    
    return timeinfo->tm_min;
}

int gpio_export(int pin)
{
	char buf[128] = {0};
	char file[128] = {0};

	sprintf(file, "/sys/class/gpio/export");
	int fd = open(file, O_WRONLY);
	if(fd > 0) {
		sprintf(buf, "%d", pin);
		write(fd, buf, strlen(buf));
		close(fd);
		return 0;
	}

	return -1;
}

int gpio_direction_out(int pin)
{
	char buf[128] = {0};
	char file[128] = {0};

	sprintf(file, "/sys/class/gpio/gpio%d/direction", pin);
	int fd = open(file, O_WRONLY);
	if(fd > 0) {
		sprintf(buf, "out");
		write(fd, buf, strlen(buf));
		close(fd);
		return 0;
	}

	return -1;
}

int gpio_direction_in(int pin)
{
	char buf[128] = {0};
	char file[128] = {0};

	sprintf(file, "/sys/class/gpio/gpio%d/direction", pin);
	int fd = open(file, O_WRONLY);
	if(fd > 0) {
		sprintf(buf, "in");
		write(fd, buf, strlen(buf));
		close(fd);
		return 0;
	}

	return -1;
}

int gpio_value_output(int pin, int level)
{
	char buf[128] = {0};
	char file[128] = {0};

	sprintf(file, "/sys/class/gpio/gpio%d/value", pin);

	int fd = open(file, O_WRONLY);
	if(fd > 0) {
		sprintf(buf, "%d", level);
		write(fd, buf, strlen(buf));
		close(fd);
		return 0;
	}

	return -1;
}

int get_gpio_value(int pin)
{
	char buf[128] = {0};
	char file[128] = {0};
	int value = 0;

	sprintf(file, "/sys/class/gpio/gpio%d/value", pin);

	int fd = open(file, O_RDONLY);
	if(fd > 0) {
		read(fd, buf, sizeof(buf));
		close(fd);
		value = atoi(buf);
		return value;
	}

	return -1;
}

void get_serial_number(char * Serial)
{
	int fd;

	fd = open("/sys/firmware/devicetree/base/serial-number", O_RDONLY);
	if(fd > 0) {
		read(fd, Serial, 16);
		close(fd);
	}
}

int get_file_md5sum(char *filename, char *md5sum)
{
#if 0
	int maxline;
	char cmd[256] = {0};
	char out[256] = {0};
	maxline = 1;
	sprintf(cmd, "md5sum %s", filename);
	myexec(cmd, out, &maxline);
	out[32] = 0;
	strcpy(md5sum, out);
#else
	int ret = -1;
	int fd;
	struct stat file_stat;
	unsigned char *filebuf = NULL;

	MD5_CTX c = {0};
	unsigned char md[MD5_DIGEST_LENGTH];
	char md5str[64] = {0};

	fd = open(filename, O_RDONLY);
	if(fd > 0)
	{
		fstat(fd, &file_stat);
		filebuf = malloc(file_stat.st_size);
		if(filebuf)
		{
			read(fd, filebuf, file_stat.st_size);
			//MD5((const unsigned char *)filebuf, file_stat.st_size, md);
			MD5_Init(&c);
			MD5_Update(&c, filebuf, file_stat.st_size);
			MD5_Final(md, &c);
			hex2string_lowercase(md5str, md, MD5_DIGEST_LENGTH);
			strcpy(md5sum, md5str);
			//DEBUG("%s", md5str);
			free(filebuf);
			ret = 0;
		}

		close(fd);
	}
#endif

	return ret;
}

